import os
from datetime import datetime
from enum import Enum

class LogLevel(Enum):
    INFO = "info"
    ERROR = "error"
    DETECTION = "detection"

class FileLogger:
    """
    针对单一日志文件的写入器。
    - file_path: 完整的日志文件路径
    - verbose: 是否同时在控制台打印
    """
    def __init__(self, file_path: str, verbose: bool = False):
        self.file_path = file_path
        self.verbose = verbose

        # 确保目录存在
        os.makedirs(os.path.dirname(file_path), exist_ok=True)

        # 确保文件存在
        if not os.path.exists(file_path):
            open(file_path, "w", encoding="utf-8").close()

    def log(self, level: str, message: str, **fields):
        """
        将一行日志写入目标文件，可附加若干键值字段。
        :param level: 日志级别字符串，例如 "INFO"、"WARNING"、"CUSTOM" 等
        :param message: 日志主体内容
        :param fields: 可选的附加字段，会按 k=v 拼接到行尾
        """
        ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        if fields:
            field_str = " | ".join(f"{k}={v}" for k, v in fields.items())
            line = f"[{ts}] {level} | {message} | {field_str}"
        else:
            line = f"[{ts}] {level} | {message}"

        with open(self.file_path, "a", encoding="utf-8") as f:
            f.write(line + "\n")

        if self.verbose:
            print(line)

class Logger:
    def __init__(
        self,
        root_dir: str,
        verbose_info: bool = False,
        verbose_error: bool = False,
        verbose_detection: bool = False
    ):
        """
        :param root_dir: 项目根目录，用于定位 logs 目录
        :param verbose_info: 是否在控制台也打印 info 日志
        :param verbose_error: 是否在控制台也打印 error 日志
        :param verbose_detection: 是否在控制台也打印 detection 日志
        """

        # 记录 verbose 标志
        self.verbose_flags = {
            LogLevel.INFO: verbose_info,
            LogLevel.ERROR: verbose_error,
            LogLevel.DETECTION: verbose_detection
        }

        # 基础 logs 目录
        base_logs_dir = os.path.join(root_dir, "logs")
        os.makedirs(base_logs_dir, exist_ok=True)

        # 用当前时间戳作为本次运行的子目录名，格式：YYYYmmdd
        timestamp = datetime.now().strftime("%Y%m%d")
        run_dir = os.path.join(base_logs_dir, timestamp)
        os.makedirs(run_dir, exist_ok=True)

        # 保存本次运行目录，供外部查询
        self.run_dir = run_dir

        # 为三种日志类型准备文件路径
        self.log_paths = {
            LogLevel.INFO: os.path.join(run_dir, "info.log"),
            LogLevel.ERROR: os.path.join(run_dir, "error.log"),
            LogLevel.DETECTION: os.path.join(run_dir, "detection.log"),
        }

        # 初始化各文件（在首次写入时自动创建）
        for path in self.log_paths.values():
            # 保证文件存在（后续会以追加方式写入）
            if not os.path.exists(path):
                open(path, "w", encoding="utf-8").close()

        # 缓存 FileLogger 实例
        self._custom_loggers = {}

    def _write_line(self, level: LogLevel, line: str):
        """
        将一行 log 追加写入到对应文件，同时根据 verbose 标志决定是否打印到控制台。
        """
        path = self.log_paths[level]
        with open(path, "a", encoding="utf-8") as f:
            f.write(line + "\n")

        if self.verbose_flags.get(level, False):
            print(line)

    def info(self, message: str, **fields):
        """
        写入 info.log
        :param message: 日志主内容
        :param fields: 可选的多余字段，如 frame_id=123, device_id="cam01" 等
        """
        ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        if fields:
            field_str = " | ".join(f"{k}={v}" for k, v in fields.items())
            line = f"timestamp=[{ts}] | level=INFO | {message} | {field_str}"
        else:
            line = f"timestamp=[{ts}] | level=INFO | {message}"
        self._write_line(LogLevel.INFO, line)

    def error(self, message: str, **fields):
        """
        写入 error.log
        :param message: 错误或异常信息
        :param fields: 可选的额外字段，如 device_id="cam01" 等
        """
        ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        if fields:
            field_str = " | ".join(f"{k}={v}" for k, v in fields.items())
            line = f"timestamp=[{ts}] | level=ERROR | {message} | {field_str}"
        else:
            line = f"timestamp=[{ts}] | level=ERROR | {message}"
        self._write_line(LogLevel.ERROR, line)

    def detection(self, status: str, defect_type: str, confidence: float, **fields):
        """
        写入 detection.log，专门用于记录每帧检测结果

        :param status: 缺陷状态，例如 "defective" 或 "normal"
        :param defect_type: 缺陷类型，如 "scratch", "inclusion" 等
        :param confidence: 置信度，浮点数
        :param fields: 可选额外字段，如 frame_id=123, image_path="xxx.jpg" 等
        """
        ts = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
        base_str = f"status={status} | type={defect_type} | confidence={confidence:.2f}"
        if fields:
            other_str = " | ".join(f"{k}={v}" for k, v in fields.items())
            line = f"timestamp=[{ts}] | level=DETECTION | {base_str} | {other_str}"
        else:
            line = f"timestamp=[{ts}] | level=DETECTION | {base_str}"
        self._write_line(LogLevel.DETECTION, line)

    def get_logger(self, name: str, verbose: bool = False):
        """
        获取或创建一个自定义 Logger，用于写入 run_dir 下指定名称的文件（例如 "custom.log"）。
        - 如果已请求过同名 logger，则返回同一个实例。
        - name 可以不带后缀，也可以带 ".log"；如果不带，则自动添加 ".log"。

        :param name: 日志文件名（如 "metrics" 或 "metrics.log"）
        :param verbose: 是否同时在控制台打印

        :return: FileLogger 实例
        """
        # 保证以 .log 结尾
        if not name.endswith(".log"):
            name = f"{name}.log"
        # 目标文件完整路径
        file_path = os.path.join(self.run_dir, name)

        if name not in self._custom_loggers:
            # 创建新的 FileLogger 并缓存
            self._custom_loggers[name] = FileLogger(file_path, verbose=verbose)
        return self._custom_loggers[name]

# 全局 logger 实例，供外部使用
_global_logger = None

def set_global_logger(logger_instance):
    """
    设置全局 logger 实例，供外部使用。
    """
    global _global_logger
    _global_logger = logger_instance

def get_global_logger():
    """
    获取全局 logger 实例，供外部使用。
    """
    return _global_logger